package com.agile.leetcode.tomcat.nio;

import com.agile.leetcode.tomcat.abstractservlet.MyHttpServlet;
import com.agile.leetcode.tomcat.servletscanner.AddressScanner;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author KD
 * @Date 2021/2/7 10:25
 */
@SuppressWarnings("all")
public class NioServer {
    /**
     * 端口
     */
    private int port;
    /**
     * 选择器
     */
    private Selector selector;
    /**
     * 服务器
     */
    private ServerSocketChannel serverSocketChannel;

    public NioServer(int port) throws IOException {
        // 端口
        this.port = port;
        //
        selector = Selector.open();
        //
        serverSocketChannel = ServerSocketChannel.open();
        // 监听端口
        serverSocketChannel.bind(new InetSocketAddress(this.port));
        // 配置非阻塞
        serverSocketChannel.configureBlocking(false);
        // 注册到选择器上
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    public void start() {
        try {
            // 初始化扫描
            AddressScanner.scan("com.agile.leetcode.tomcat.servlet");
            // 是否有链接进来
            while (true) {
                int i = selector.select();
                if (i > 0) {
                    // 有链接进来
                    // 迭代
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        // 拿到下一个
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        // 判断状态
                        if (key.isAcceptable()) {
                            // 接收
                            // 此时走到这一步按理说就不是阻塞的
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            // 配置非阻塞
                            socketChannel.configureBlocking(false);
                            // 设置状态
                            socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                            // 输出
                            System.out.println(socketChannel.getRemoteAddress() + "连接了");
                        }
                        if (key.isReadable()) {
                            // 分发请求
                            doDispatch(key);
                        }
                    }
                }
            }
        } catch (Exception ex) {

        }
    }

    private void doDispatch(SelectionKey key) throws IOException, InstantiationException, IllegalAccessException {
        // 封装对象
        MyNioRequest request = new MyNioRequest(key);
        MyNioResponse response = new MyNioResponse(key);
        // 执行任务
        executeTask(request, response);
    }

    private void executeTask(MyNioRequest request, MyNioResponse response) throws IllegalAccessException, InstantiationException {
        // 拿到url
        String url = request.getUrl();
        // 在map中匹配
        Map<String, Class> map = AddressScanner.getAddress();
        Class clazz = map.get(url);
        if (clazz != null) {
            // 创建对象
            MyHttpServlet servlet = (MyHttpServlet) clazz.newInstance();
            // 执行方法
            servlet.service(request, response);
        } else {
            throw new RuntimeException("没有找到对应的handler");
        }
    }
}
